#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <functional>
#include "Log.hpp"
#include "Connection.hpp"
#include <string>

class HandlerConnection;
class Connection;

class HandlerConnection
{
public:
    HandlerConnection(func_t func)
        : _func(func)
    {
    }
    ~HandlerConnection()
    {
    }

public:
    void HandlerRecv(Connection *conn)
    {
        errno = 0;
        LOG(DEBUG, "HanlderRecv fd : %d\n", conn->Sockfd());
        while (true)
        {
            char buffer[1024];
            int n = ::recv(conn->Sockfd(), buffer, sizeof(buffer) - 1, 0); // 已经设置非阻塞了
            if (n > 0)
            {
                // 不断添加到inbuffer里面
                buffer[n] = 0;
                conn->AppendInbuffer(buffer);
            }
            else
            {
                // 读完了, 就阻塞了
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break;
                }
                // 由于信号中断，继续下一次读就好了
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    // 读出错了
                    conn->_excepter(conn); // 由于当初遇到错误是转换成立读写的处理，那么倒逼一定会这里读出错，就异常处理
                    return;                // 一定要提前返回
                }
            }
        }
        _func(conn); // 这里读完了，就回调上层协议，处理完整报文
    }
    void HandlerSend(Connection *conn)
    {
        errno = 0;
        while (true)
        {
            // 将输出缓冲区里面的发送出去
            ssize_t n = ::send(conn->Sockfd(), conn->Outbuffer().c_str(), conn->Outbuffer().size(), 0);
            if (n > 0)
            {
                // n实际发了多少
                conn->OutbufferRemove(n); // 将发送出去了的，从输出缓冲区移除
                // 如果为空说明发完了，结束break
                if (conn->OutbufferEmpty())
                    break;
            }
            else if (n == 0)
            {
                break;
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break; // 只有这里会跳出循环，向下执行 输出缓冲区写满了
                }
                else if (errno == EINTR)
                {
                    continue; // 信号中断
                }
                else
                {
                    conn->_excepter(conn);
                    return; // 一定要提前返回
                }
            }
        }

        if (!conn->OutbufferEmpty())
        {
            // 一定遇到了，发送缓冲区被写满的情况
            // 只需要开启对应的事件读写关心，然后下次继续交给Reactor关心，等就绪了再发
            conn->_R->EnableReadWrite(conn->Sockfd(), true, true);
        }
        else
        {
            // 发送完了，取消读写关心，下次不用关心了
            conn->_R->EnableReadWrite(conn->Sockfd(), true, false);
        }
    }
    void HandlerExcept(Connection *conn)
    {
        errno = 0;
        LOG(DEBUG, "client quit : %d\n", conn->Sockfd());
        conn->_R->RemoveConnection(conn->Sockfd());
    }

private:
    func_t _func;
};